
/*
 * Main.java
 *
 * Created on May 25, 2011, 8:34:34 AM
 */
package pvjscript;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Properties;
import java.util.Stack;
import java.util.concurrent.LinkedBlockingQueue;
import javax.swing.JFileChooser;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JScrollBar;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.table.DefaultTableModel;
import javax.swing.text.AttributeSet;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.Style;

/**
 *
 * @author shackle
 */
public class Main extends javax.swing.JFrame {

    /** Creates new form Main */
    public Main() {
        initComponents();
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jDialogEnvp = new javax.swing.JDialog();
        jScrollPaneEnvpTable = new javax.swing.JScrollPane();
        jTableEnvp = new javax.swing.JTable();
        buttonGroupVw = new javax.swing.ButtonGroup();
        jScrollPane1 = new javax.swing.JScrollPane();
        jTextPane1 = new javax.swing.JTextPane();
        jTextFieldCmd = new javax.swing.JTextField();
        jMenuBar1 = new javax.swing.JMenuBar();
        jMenu1 = new javax.swing.JMenu();
        jMenuItemOpen = new javax.swing.JMenuItem();
        jMenuProcess = new javax.swing.JMenu();
        jMenu2 = new javax.swing.JMenu();
        jRadioButtonMenuItemViewStdOut = new javax.swing.JRadioButtonMenuItem();
        jRadioButtonMenuItemViewStdErr = new javax.swing.JRadioButtonMenuItem();
        jRadioButtonMenuItemViewBoth = new javax.swing.JRadioButtonMenuItem();
        jRadioButtonMenuItemViewDebug = new javax.swing.JRadioButtonMenuItem();
        jMenuTools = new javax.swing.JMenu();
        jMenuItem1 = new javax.swing.JMenuItem();
        jMenuItem2 = new javax.swing.JMenuItem();
        jMenuOptions = new javax.swing.JMenu();
        jCheckBoxMenuItemAutoScroll = new javax.swing.JCheckBoxMenuItem();
        jMenuItemSetScrollLimit = new javax.swing.JMenuItem();

        jTableEnvp.setAutoCreateRowSorter(true);
        jTableEnvp.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {
                {null, null},
                {null, null},
                {null, null},
                {null, null}
            },
            new String [] {
                "Env Variable", "Env Value"
            }
        ) {
            Class[] types = new Class [] {
                java.lang.String.class, java.lang.String.class
            };
            boolean[] canEdit = new boolean [] {
                false, false
            };

            public Class getColumnClass(int columnIndex) {
                return types [columnIndex];
            }

            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return canEdit [columnIndex];
            }
        });
        jScrollPaneEnvpTable.setViewportView(jTableEnvp);

        javax.swing.GroupLayout jDialogEnvpLayout = new javax.swing.GroupLayout(jDialogEnvp.getContentPane());
        jDialogEnvp.getContentPane().setLayout(jDialogEnvpLayout);
        jDialogEnvpLayout.setHorizontalGroup(
            jDialogEnvpLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jDialogEnvpLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jScrollPaneEnvpTable, javax.swing.GroupLayout.DEFAULT_SIZE, 419, Short.MAX_VALUE)
                .addContainerGap())
        );
        jDialogEnvpLayout.setVerticalGroup(
            jDialogEnvpLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jDialogEnvpLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jScrollPaneEnvpTable, javax.swing.GroupLayout.DEFAULT_SIZE, 372, Short.MAX_VALUE)
                .addContainerGap())
        );

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                formWindowClosing(evt);
            }
            public void windowClosed(java.awt.event.WindowEvent evt) {
                formWindowClosed(evt);
            }
        });

        jTextPane1.setEditable(false);
        jScrollPane1.setViewportView(jTextPane1);

        jTextFieldCmd.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jTextFieldCmdActionPerformed(evt);
            }
        });

        jMenu1.setText("File");

        jMenuItemOpen.setText("Open ...");
        jMenuItemOpen.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItemOpenActionPerformed(evt);
            }
        });
        jMenu1.add(jMenuItemOpen);

        jMenuBar1.add(jMenu1);

        jMenuProcess.setText("Process");
        jMenuBar1.add(jMenuProcess);

        jMenu2.setText("View");
        buttonGroupVw.add(jMenu2);

        buttonGroupVw.add(jRadioButtonMenuItemViewStdOut);
        jRadioButtonMenuItemViewStdOut.setText("View Std Out");
        jRadioButtonMenuItemViewStdOut.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jRadioButtonMenuItemViewStdOutActionPerformed(evt);
            }
        });
        jMenu2.add(jRadioButtonMenuItemViewStdOut);

        buttonGroupVw.add(jRadioButtonMenuItemViewStdErr);
        jRadioButtonMenuItemViewStdErr.setText("View Std Err");
        jRadioButtonMenuItemViewStdErr.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jRadioButtonMenuItemViewStdErrActionPerformed(evt);
            }
        });
        jMenu2.add(jRadioButtonMenuItemViewStdErr);

        buttonGroupVw.add(jRadioButtonMenuItemViewBoth);
        jRadioButtonMenuItemViewBoth.setSelected(true);
        jRadioButtonMenuItemViewBoth.setText("View Both Std Out and Err");
        jRadioButtonMenuItemViewBoth.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jRadioButtonMenuItemViewBothActionPerformed(evt);
            }
        });
        jMenu2.add(jRadioButtonMenuItemViewBoth);

        buttonGroupVw.add(jRadioButtonMenuItemViewDebug);
        jRadioButtonMenuItemViewDebug.setText("View All and Debug");
        jRadioButtonMenuItemViewDebug.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jRadioButtonMenuItemViewDebugActionPerformed(evt);
            }
        });
        jMenu2.add(jRadioButtonMenuItemViewDebug);

        jMenuBar1.add(jMenu2);

        jMenuTools.setText("Tools");

        jMenuItem1.setText("Show Environment ...");
        jMenuItem1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem1ActionPerformed(evt);
            }
        });
        jMenuTools.add(jMenuItem1);

        jMenuItem2.setText("Kill this process");
        jMenuItem2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem2ActionPerformed(evt);
            }
        });
        jMenuTools.add(jMenuItem2);

        jMenuBar1.add(jMenuTools);

        jMenuOptions.setText("Options");

        jCheckBoxMenuItemAutoScroll.setSelected(true);
        jCheckBoxMenuItemAutoScroll.setText("Automatically Scroll");
        jMenuOptions.add(jCheckBoxMenuItemAutoScroll);

        jMenuItemSetScrollLimit.setText("Set Scroll Limit ...");
        jMenuItemSetScrollLimit.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItemSetScrollLimitActionPerformed(evt);
            }
        });
        jMenuOptions.add(jMenuItemSetScrollLimit);

        jMenuBar1.add(jMenuOptions);

        setJMenuBar(jMenuBar1);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jTextFieldCmd, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
            .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 244, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jTextFieldCmd, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents
    private void jMenuItemOpenActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemOpenActionPerformed
        this.BrowseOpenScriptFile();
    }//GEN-LAST:event_jMenuItemOpenActionPerformed

    private void setViewState() {
        if (this.jRadioButtonMenuItemViewStdOut.isSelected()) {
            this.vw_state = ViewState.ViewStdOut;
        } else if (this.jRadioButtonMenuItemViewStdErr.isSelected()) {
            this.vw_state = ViewState.ViewStdErr;
        } else if (this.jRadioButtonMenuItemViewBoth.isSelected()) {
            this.vw_state = ViewState.ViewStdOutAndStdErr;
        } else if (this.jRadioButtonMenuItemViewDebug.isSelected()) {
            this.vw_state = ViewState.ViewStdOutAndStdErrAndDebug;
        } else {
            System.err.println("Bad radio button state!");
            this.vw_state = ViewState.ViewStdOutAndStdErr;
            this.jRadioButtonMenuItemViewBoth.setSelected(true);
        }
        this.updateTextPane();
    }
    private void jRadioButtonMenuItemViewStdOutActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jRadioButtonMenuItemViewStdOutActionPerformed
        setViewState();
    }//GEN-LAST:event_jRadioButtonMenuItemViewStdOutActionPerformed

    private void jRadioButtonMenuItemViewStdErrActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jRadioButtonMenuItemViewStdErrActionPerformed
        setViewState();
    }//GEN-LAST:event_jRadioButtonMenuItemViewStdErrActionPerformed

    private void jRadioButtonMenuItemViewBothActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jRadioButtonMenuItemViewBothActionPerformed
        setViewState();
    }//GEN-LAST:event_jRadioButtonMenuItemViewBothActionPerformed

    private void jMenuItem1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem1ActionPerformed
        this.ShowEnvironment();
    }//GEN-LAST:event_jMenuItem1ActionPerformed

    private void jMenuItemSetScrollLimitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemSetScrollLimitActionPerformed
        String s = JOptionPane.showInputDialog("Max Characters to Keep?", ProcessView.BUF_LIMIT);
        if (s != null) {
            ProcessView.BUF_LIMIT = Integer.valueOf(s);
        }
    }//GEN-LAST:event_jMenuItemSetScrollLimitActionPerformed

    private void jTextFieldCmdActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jTextFieldCmdActionPerformed
        try {
            if (null == this.mainThread) {
                this.startMainThread();
            }
            String l = this.jTextFieldCmd.getText();
            if (null == scriptPv) {
                this.setDir(new File(System.getProperty("user.dir")));
                this.initEnvp();
                scriptPv = this.createPv(l);
            }
            CurrentPv = this.scriptPv;
            scriptPv.appendOut("cmd> " + l);
            this.lineQueue.add(this.jTextFieldCmd.getText());
            this.updateTextPane();
            this.jTextFieldCmd.setText("");
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }//GEN-LAST:event_jTextFieldCmdActionPerformed

    private void formWindowClosed(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosed
        this.close();
    }//GEN-LAST:event_formWindowClosed

    private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing
        this.close();
    }//GEN-LAST:event_formWindowClosing

    private void jMenuItem2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem2ActionPerformed
        if (null != CurrentPv) {
            CurrentPv.close();
        }
    }//GEN-LAST:event_jMenuItem2ActionPerformed

    private void jRadioButtonMenuItemViewDebugActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jRadioButtonMenuItemViewDebugActionPerformed
        setViewState();
    }//GEN-LAST:event_jRadioButtonMenuItemViewDebugActionPerformed

    private enum ViewState {

        ViewStdOut,
        ViewStdErr,
        ViewStdOutAndStdErr,
        ViewStdOutAndStdErrAndDebug,
    };
    private ViewState vw_state = ViewState.ViewStdOutAndStdErr;
    AttributeSet origCa = null;
    DefaultStyledDocument outDoc = new DefaultStyledDocument();
    DefaultStyledDocument errDoc = new DefaultStyledDocument();

    private void updateTextPane() {
        if (origCa == null) {
            origCa = this.jTextPane1.getCharacterAttributes();
        }
        if (null == this.CurrentPv) {
            this.jTextPane1.setText("");
        } else {
            switch (vw_state) {
                case ViewStdOut:
                    this.jTextPane1.setStyledDocument(outDoc);
                    this.jTextPane1.setForeground(Color.black);
                    this.jTextPane1.setCharacterAttributes(this.CurrentPv.getOutStyle(), true);
                    this.jTextPane1.setText(this.CurrentPv.getOut());
                    this.jTextPane1.setForeground(Color.black);
                    this.jTextPane1.setCharacterAttributes(this.CurrentPv.getOutStyle(), true);
                    break;

                case ViewStdErr:
                    this.jTextPane1.setStyledDocument(errDoc);
                    this.jTextPane1.setForeground(Color.red);
                    this.jTextPane1.setCharacterAttributes(this.CurrentPv.getErrStyle(), true);
                    this.jTextPane1.setText(this.CurrentPv.getErr());
                    this.jTextPane1.setForeground(Color.red);
                    this.jTextPane1.setCharacterAttributes(this.CurrentPv.getErrStyle(), true);
                    break;

                case ViewStdOutAndStdErr:
                    //this.jTextPane1.setText(null);
                    this.jTextPane1.setCharacterAttributes(origCa, true);
                    this.jTextPane1.setStyledDocument(this.CurrentPv.getOutPlusErr());
                    break;

                case ViewStdOutAndStdErrAndDebug:
                    //this.jTextPane1.setText(null);
                    this.jTextPane1.setCharacterAttributes(origCa, true);
                    this.jTextPane1.setStyledDocument(this.CurrentPv.getOutPlusErrPlusDebug());
                    break;
            }
        }
    }
    protected String LastScriptDir;

    /**
     * Get the value of LastScriptDir
     *
     * @return the value of LastScriptDir
     */
    public String getLastScriptDir() {
        return LastScriptDir;
    }

    /**
     * Set the value of LastScriptDir
     *
     * @param LastScriptDir new value of LastScriptDir
     */
    public void setLastScriptDir(String LastScriptDir) {
        this.LastScriptDir = LastScriptDir;
    }

    private void BrowseOpenScriptFile() {
        try {
            JFileChooser chooser = new JFileChooser();
            if (null != this.LastScriptDir) {
                chooser.setCurrentDirectory(new File(this.LastScriptDir));
            }
            FileNameExtensionFilter pvjscript_file_filter = new FileNameExtensionFilter("pvjscript", "pvjscript");
            chooser.addChoosableFileFilter(pvjscript_file_filter);
            chooser.setFileFilter(pvjscript_file_filter);
            chooser.setMultiSelectionEnabled(true);
            int returnVal = chooser.showOpenDialog(this);
            if (returnVal == JFileChooser.APPROVE_OPTION) {
                File fa[] = chooser.getSelectedFiles();
                for (int i = 0; i < fa.length; i++) {
                    final File f = fa[i];
                    System.out.println("You chose to open this file: "
                            + f.getPath());
                    File dir1 = chooser.getCurrentDirectory();
                    this.setLastScriptDir(dir1.getAbsolutePath());
                    if (null == this.mainThread) {
                        this.startMainThread();
                    }
                    this.lineQueue.add(f.getCanonicalPath());
                }
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }

    private void ShowEnvironment() {
        this.jDialogEnvp.setVisible(false);
        this.jDialogEnvp.setTitle("Environment for " + CurrentPv);
        DefaultTableModel model = (DefaultTableModel) this.jTableEnvp.getModel();
        String envpA[] = envp;
        if (null != this.CurrentPv) {
            envpA = this.CurrentPv.getEnvp();
        }
        if (null != envpA) {
            model.setRowCount(envpA.length);
            for (int i = 0; i < envpA.length; i++) {
                int eqindex = envpA[i].indexOf('=');
                if (eqindex > 0) {
                    String var = envpA[i].substring(0, eqindex);
                    String val = envpA[i].substring(eqindex + 1);
                    model.setValueAt(var, i, 0);
                    model.setValueAt(val, i, 1);
                }
            }
        }
        this.jDialogEnvp.pack();
        this.jDialogEnvp.setVisible(true);
    }
    protected LinkedList<ProcessView> JobsList;

    /**
     * Get the value of JobsList
     *
     * @return the value of JobsList
     */
    public LinkedList<ProcessView> getJobsList() {
        return JobsList;
    }

    /**
     * Set the value of JobsList
     *
     * @param JobsList new value of JobsList
     */
    public void setJobsList(LinkedList<ProcessView> JobsList) {
        this.JobsList = JobsList;
    }
    protected ProcessView CurrentPv;

    /**
     * Get the value of CurrentPv
     *
     * @return the value of CurrentPv
     */
    public ProcessView getCurrentPv() {
        return CurrentPv;
    }

    /**
     * Set the value of CurrentPv
     *
     * @param CurrentPv new value of CurrentPv
     */
    public void setCurrentPv(ProcessView CurrentPv) {
        this.CurrentPv = CurrentPv;
    }
    String val0 = "";
    HashMap<String, String> tmpVars = null;

    private String getval(String s) {
        try {
            if (s.compareTo("0") == 0) {
                return val0;
            }
            if (null != tmpVars) {
                String v = tmpVars.get(s);
                if (null != v) {
                    return v;
                }
            }
            if (null != envp) {
                for (int i = 0; i < envp.length; i++) {
                    if (envp[i].startsWith(s + "=")) {
                        return envp[i].substring(s.length() + 1);
                    }
                }
            }
            
            
            java.util.Properties p = System.getProperties();
            if (p != null) {
                String v = p.getProperty(s);
                if (v != null) {
                    return v;
                }
            }
            String ev = System.getenv(s);
            if (null != ev) {
                return ev;
            }
            if (s.compareTo("RCSLIB_DIR") == 0) {
                return this.find_rcslib_dir();
            }
            return this.query_val(s);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    public void close() {
        try {
            if (null != this.JobsList) {
                for (final ProcessView pv : JobsList) {
                    pv.close();
                }
            }
            this.JobsList = null;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    protected void finalize() throws Throwable {
        super.finalize();
        close();
    }

    public void updateProcessMenu() {
        this.jMenuProcess.removeAll();
        if (null != this.JobsList) {
            for (final ProcessView pv : JobsList) {
                JMenuItem jmi = new JMenuItem(pv.toString());
                jmi.addActionListener(new ActionListener() {

                    public void actionPerformed(ActionEvent e) {
                        CurrentPv = pv;
                        updateTextPane();
                    }
                });
                this.jMenuProcess.add(jmi);
            }
        }
    }
    protected File dir;

    /**
     * Get the value of dir
     *
     * @return the value of dir
     */
    public File getDir() {
        return dir;
    }

    /**
     * Set the value of dir
     *
     * @param dir new value of dir
     */
    public void setDir(File dir) {
        this.dir = dir;
        if (null != scriptPv) {
            scriptPv.setDir(dir);
        }
    }
    protected String[] envp;

    /**
     * Get the value of envp
     *
     * @return the value of envp
     */
    public String[] getEnvp() {
        return envp;
    }

    /**
     * Set the value of envp
     *
     * @param envp new value of envp
     */
    public void setEnvp(String[] envp) {
        this.envp = envp;
        if (null != scriptPv) {
            scriptPv.setEnvp(envp);
        }
    }

    private void scrollToEnd() {
        JScrollBar vbar = this.jScrollPane1.getVerticalScrollBar();
        vbar.setValue(vbar.getMaximum());
    }

    private ProcessView createPv(String l) {
        ProcessView pv = new ProcessView(l.trim());
        if (null != dir) {
            pv.setDir(dir);
        }
        if (null != envp) {
            pv.setEnvp(envp.clone());
        }
        pv.addPropertyChangeListener(
                new PropertyChangeListener() {

                    public void propertyChange(PropertyChangeEvent evt) {
                        if (evt.getSource() == CurrentPv
                                || null == CurrentPv) {
                            java.awt.EventQueue.invokeLater(new Runnable() {

                                public void run() {
                                    updateTextPane();
                                    if (jCheckBoxMenuItemAutoScroll.isSelected()) {
                                        scrollToEnd();
                                    }
                                }
                            });
                        }
                    }
                });
        return pv;
    }

    public String RunCmd(String l) throws Exception {
        String piped_cmds[] = l.split("[|]");
        if (null != piped_cmds && piped_cmds.length > 1) {
            ProcessView pva[] = new ProcessView[piped_cmds.length];
            for (int i = 0; i < piped_cmds.length; i++) {
                pva[i] = this.createPv(piped_cmds[i]);
                //this.addJob(pva[i]);
            }
            for (int i = piped_cmds.length - 1; i >= 0; i--) {
                if (i < piped_cmds.length - 1) {
                    pva[i].setPipedOutput(pva[i + 1].getOutputStream());
                }
                pva[i].Start(scriptPv);
            }
            pva[0].waitFor();
            for (int i = 0; i < pva.length; i++) {
                pva[i].close();
            }
            String r = pva[pva.length - 1].getOut();
            return r;
        }
        switch (checkBuiltIns(this.splitArgs(l))) {
            case 0:
                return builtin_output;

            case 1:
                return builtin_output;
        }
        ProcessView pv = this.createPv(l);
        pv.Start(scriptPv);
        pv.waitFor();
        pv.close();
        Thread.sleep(200);
        return pv.getOut();
    }
    private String builtin_output = "";

    private String replaceVar(String in) {
        if (in.startsWith("$")) {
            String aftervar = in.substring(1);
            String var = "";
            while (aftervar.length() > 0
                    && Character.isJavaIdentifierPart(aftervar.charAt(0))) {
                var += aftervar.substring(0, 1);
                aftervar = aftervar.substring(1);
            }
            in = getval(var) + aftervar;
        } else if (in.startsWith("2>/dev/null")) {
            in = "";
        }
        return in;
    }

    private String[] splitArgs(String l) {
        LinkedList<String> argsl = new LinkedList<String>();
        boolean inside_double_quotes = false;
        boolean inside_single_quotes = false;
        boolean inside_back_quotes = false;
        boolean quoted_arg = false;
        String next_arg = "";
        while (l.length() > 0) {
            char c = l.charAt(0);
//            if (c == '\\'
//                    && l.charAt(1) != '*'
//                    && l.charAt(1) != '?') {
//                next_arg += l.charAt(1);
//                l = l.substring(2);
//                continue;
//            }
            if (c == '`') {
                inside_back_quotes = !inside_back_quotes;
                quoted_arg = true;
                next_arg += c;
                l = l.substring(1);
                continue;
            }
            if (inside_back_quotes) {
                next_arg += c;
                l = l.substring(1);
                continue;
            }
            if (c == '\'') {
                inside_single_quotes = !inside_single_quotes;
                quoted_arg = true;
                l = l.substring(1);
                continue;
            }
            if (inside_single_quotes) {
                next_arg += c;
                l = l.substring(1);
                continue;
            }
            if (c == '"') {
                inside_double_quotes = !inside_double_quotes;
                quoted_arg = true;
                l = l.substring(1);
                continue;
            }
            if (inside_double_quotes) {
                next_arg += c;
                l = l.substring(1);
                continue;
            }
            if (c == ' ' || c == '\t') {
                if (next_arg.length() > 0) {
                    if (!quoted_arg) {
                        argsl.add(this.replaceVar(next_arg));
                    } else {
                        argsl.add(next_arg);
                    }
                }
                next_arg = "";
                l = l.substring(1);
                quoted_arg = false;
                continue;
            }
            next_arg += c;
            l = l.substring(1);
        }
        if (next_arg.length() > 0) {
            if (!quoted_arg) {
                argsl.add(this.replaceVar(next_arg));
            } else {
                argsl.add(next_arg);
            }
        }
        String args[] = new String[argsl.size()];
        return argsl.toArray(args);
    }
    private Stack<Boolean> ifStateStack = new Stack<Boolean>();
    private boolean current_ifstate = true;

    File strToFile(String s) {
        File f = new File(s);
        if (f.isAbsolute() && f.getParentFile().exists()) {
            return f;
        }
        if (s.startsWith("./")) {
            s = s.substring(2);
        }
        String pathElem[] = s.split("/+");
        if (s.startsWith("/")) {
            f = new File(File.separator + pathElem[0]);
        } else {
            if (pathElem[0].compareTo("..") == 0) {
                f = dir.getParentFile();
            } else {
                f = new File(dir, pathElem[0]);
            }
        }
        for (int i = 1; i < pathElem.length; i++) {
            if (pathElem[i].compareTo("..") == 0) {
                f = f.getParentFile();
            } else {
                f = new File(f, pathElem[i]);
            }
        }
        return f;
    }

    String arrayToStr(String args[]) {
        return arrayToStr(args, 0);
    }

    String arrayToStr(String args[], int starting_arg) {
        if (args == null || args.length < 1) {
            return "";
        }
        String out = args[starting_arg];
        for (int i = starting_arg + 1; i < args.length; i++) {
            out += " " + args[i];
        }
        return out;
    }

    private class forEntry {

        long seek_to;
        String var;
        String argsleft[];
    }
    private Stack<forEntry> forStack = null;
    private boolean last_cmd_was_builtin = false;

    private int checkBuiltIns(String args[]) throws Exception {
        builtin_output = "";
        last_cmd_was_builtin = true;
        if (args[0].startsWith("\\")) {
            args[0] = args[0].substring(1);
        }
        if (args[0].compareTo("waitfor") == 0) {
            if (args.length < 3) {
                appendErr("bad waitfor syntax: need 2 args :" + arrayToStr(args));
                return 0;
            }
            long timeout = Long.valueOf(args[1]) * 1000;
            final String fname = args[2];
            File wf = this.strToFile(fname);
            if(!wf.exists() && this.last_line_through_exception) {
                if(JOptionPane.showConfirmDialog(this, "Wait for "+wf.toString()+"?") != JOptionPane.YES_OPTION) {
                    return 0;
                }
            }
            long stime = System.currentTimeMillis();
            appendDebug("waiting up to " + (timeout / 1000) + " seconds for the file \"" + wf.getCanonicalPath() + "\" to exist ...");
            while (!wf.exists()
                    && (timeout < 0
                    || System.currentTimeMillis() - stime < timeout)) {
                Thread.sleep(200);
                wf = this.strToFile(fname);
            }
            if (timeout > 0
                    && System.currentTimeMillis() - stime > timeout) {
                appendErr("Timed out waiting for " + wf.getAbsolutePath());
                if (JOptionPane.showConfirmDialog(this, "Timed out waiting for " + fname + ". Continue?") != JOptionPane.YES_OPTION) {
                    return 1;
                }
            }
            return 0;
        } else if (args[0].compareTo("cd") == 0) {
            if (args.length != 2) {
                appendErr("bad cd syntax: need 1 args :" + Arrays.toString(args));
                return 0;
            }
            File f = this.strToFile(args[1]);
            if (!f.exists()) {
                appendErr(f.getCanonicalPath() + " does not exist.");
                return 0;
            }
            if (!f.isDirectory()) {
                appendErr(f.getCanonicalPath() + " does not exist.");
                return 0;
            }
            this.setDir(f);
            return 0;
        } else if (args[0].compareTo("dirname") == 0) {
            File tf = strToFile(args[1]);
            builtin_output = tf.getParentFile().getCanonicalPath();
            return 0;
        } else if (args[0].compareTo("echo") == 0) {
            builtin_output = args[1];
            for (int i = 2; i < args.length; i++) {
                builtin_output += " " + args[i];
            }
            return 0;
        } else if (args[0].compareTo("export") == 0) {
            for (int i = 1; i < args.length; i++) {
                int eqindex = args[i].indexOf('=');
                if (eqindex > 0) {
                    this.addEnvVar(args[i].substring(0, eqindex), args[i].substring(eqindex + 1));
                }
            }
            return 0;
        } else if (args[0].compareTo("exit") == 0) {
            return 1;
        } else if (args[0].compareTo("rm") == 0) {
            for (int i = 1; i < args.length; i++) {
                if (args[i].startsWith("-")) {
                    continue;
                }
                File f = this.strToFile(args[i]);
                if (f.exists()) {
                    f.delete();
                } else {
                    this.appendErr("rm: " + f.getCanonicalPath() + " does not exist.");
                }
            }
            return 0;
        } else if (args[0].compareTo("if") == 0) {
            if (args[1].compareTo("test") == 0) {
                for (int i = 2; i < args.length; i++) {
                    if (args[i].compareTo("!") == 0) {
                        current_ifstate = !current_ifstate;
                    } else if (args[i].compareTo("-o") == 0) {
                        if (current_ifstate) {
                            break;
                        }
                        current_ifstate = true;
                    } else if (args[i].compareTo("-a") == 0) {
                        if (!current_ifstate) {
                            break;
                        }
                    } else if (args[i].compareTo("-f") == 0) {
                        if (i >= args.length - 1) {
                            appendErr("bad test arguments");
                            return 1;
                        }
                        i++;
                        File fi = strToFile(args[i]);
                        if (!fi.exists() || fi.isDirectory()) {
                            current_ifstate = !current_ifstate;
                        }
                    } else if (args[i].compareTo("-e") == 0) {
                        if (i >= args.length - 1) {
                            appendErr("bad test arguments");
                            return 1;
                        }
                        i++;
                        File fi = strToFile(args[i]);
                        if (!fi.exists()) {
                            current_ifstate = !current_ifstate;
                        }
                    } else if (args[i].compareTo("-d") == 0) {
                        if (i >= args.length - 1) {
                            appendErr("bad test arguments");
                            return 1;
                        }
                        i++;
                        File fi = strToFile(args[i]);
                        if (!fi.exists() || !fi.isDirectory()) {
                            current_ifstate = !current_ifstate;
                        }
                    } else if (args[i].compareTo("-w") == 0) {
                        if (i >= args.length - 1) {
                            appendErr("bad test arguments");
                            return 1;
                        }
                        i++;
                        File fi = strToFile(args[i]);
                        if (!fi.exists() || !fi.canWrite()) {
                            current_ifstate = !current_ifstate;
                        }
                    } else if (args[i].compareTo("=") == 0) {
                        if (i >= args.length - 1 || i < 3) {
                            appendErr("bad test arguments");
                            return 1;
                        }
                        i++;
                        if (args[i - 2].compareTo(args[i]) != 0) {
                            current_ifstate = !current_ifstate;
                        }
                    } else if (args[i].compareTo("!=") == 0) {
                        if (i >= args.length - 1 || i < 3) {
                            appendErr("bad test arguments");
                            return 1;
                        }
                        i++;
                        if (args[i - 2].compareTo(args[i]) == 0) {
                            current_ifstate = !current_ifstate;
                        }
                    }
                }
            } else {
                ProcessView pv = this.createPv(arrayToStr(Arrays.copyOfRange(args, 1, args.length)));
                pv.Start(scriptPv);
                current_ifstate = (pv.waitFor() == 0);
            }
            this.ifStateStack.push(current_ifstate);
            return 0;
        } else if (args[0].compareTo("else") == 0) {
            if (this.ifStateStack.isEmpty()) {
                appendErr("else without matching if");
                return 1;
            }
            current_ifstate = !this.ifStateStack.pop();
            this.ifStateStack.push(current_ifstate);
            return 0;
        } else if (args[0].compareTo("fi") == 0) {
            if (this.ifStateStack.isEmpty()) {
                appendErr("fi without matching if");
                return 1;
            }
            this.ifStateStack.pop();
            if (this.ifStateStack.isEmpty()) {
                current_ifstate = true;
            } else {
                current_ifstate = this.ifStateStack.pop();
                this.ifStateStack.push(current_ifstate);
            }
            return 0;
        } else if (args[0].compareTo("for") == 0) {
            forEntry fe = new forEntry();
            fe.seek_to = this.script_line_num;
            fe.argsleft = Arrays.copyOfRange(args, 3, args.length);
            fe.var = args[1];
            this.appendDebug("for: fe.argsleft="+fe.argsleft.length+" \""+Arrays.toString(fe.argsleft)+"\"");
            this.appendDebug("for: fe.var="+fe.var);
            this.appendDebug("for: fe.seek_to="+fe.seek_to);
            if (fe.argsleft.length > 0) {
                if (null == forStack) {
                    forStack = new Stack<forEntry>();
                }
                forStack.push(fe);
                this.addTmpVar(fe.var, fe.argsleft[0]);
            }
            return 0;
        } else if (args[0].compareTo("done") == 0) {
            if (null == this.forStack || this.forStack.isEmpty()) {
                appendErr("done without matching for");
            }
            forEntry fe = forStack.pop();
            this.appendDebug("done: fe.argsleft="+fe.argsleft.length+" \""+Arrays.toString(fe.argsleft)+"\"");
            this.appendDebug("done: fe.var="+fe.var);
            this.appendDebug("done: fe.seek_to="+fe.seek_to);
            if (fe.argsleft.length > 1) {
                if (null != script_reader) {
                    script_reader.close();
                }
                this.script_reader = new BufferedReader(new FileReader(this.script_file));
                for (int i = 0; i < fe.seek_to-1; i++) {
                    this.script_reader.readLine();
                    //System.err.println(i + ":Skipping " + this.script_reader.readLine());
                }
                this.appendDebug("done: returning to line after:"+this.script_reader.readLine());
                this.script_line_num = (int) fe.seek_to;
                fe.argsleft = Arrays.copyOfRange(fe.argsleft, 1, fe.argsleft.length);
                if (null == forStack) {
                    forStack = new Stack<forEntry>();
                }
                forStack.push(fe);
                this.addTmpVar(fe.var, fe.argsleft[0]);
            } else if (forStack.isEmpty()) {
                forStack = null;
            }
            return 0;
        } else if (args[0].indexOf('=') > 0) {
            int eqindex = args[0].indexOf('=');
            if (eqindex > 0) {
                this.addTmpVar(args[0].substring(0, eqindex), args[0].substring(eqindex + 1)
                        + " " + this.arrayToStr(Arrays.copyOfRange(args, 1, args.length)));
                return 0;
            }
        }
        last_cmd_was_builtin = false;
        return -1;
    }
    private ProcessView scriptPv = null;

    private void addJob(ProcessView pv) {
        if (null == JobsList) {
            JobsList = new LinkedList<ProcessView>();
        }
        JobsList.add(pv);
        updateProcessMenu();
    }

    String[] expandFileGlobs(String args[]) {
        LinkedList<String> lst = new LinkedList<String>();
        for (int i = 0; i < args.length; i++) {
            if (args[i].indexOf('*') >= 0 || args[i].indexOf('?') >= 0 || args[i].indexOf('/') >= 0) {
                File f = this.strToFile(args[i]);
                File fp = f.getParentFile();
                if (fp.exists()) {
                    File fa[] = fp.listFiles();
                    if(null == fa) {
                        lst.add(args[i]);
                        continue;
                    }
                    String pattern = f.getName();
                    pattern = pattern.replaceAll("\\*", ".*");
                    pattern = pattern.replaceAll("\\?", ".");
                    for (int j = 0; j < fa.length; j++) {
                        if (fa[j].getName().matches(pattern)) {
                            lst.add(fa[j].toString());
                        }
                    }
                    continue;
                } else {
                    lst.add(args[i]);
                }
            }
            lst.add(args[i]);
        }
        String new_args[] = new String[lst.size()];
        return lst.toArray(new_args);
    }
    LinkedBlockingQueue<String> lineQueue = new LinkedBlockingQueue<String>();

    private boolean last_line_through_exception = false;

    public boolean ProcessLine(String l, boolean background) {
        try {
            if (!current_ifstate
                    && !l.startsWith("else")
                    && !l.startsWith("fi")) {
                return true;
            }

            if (l.endsWith("&")) {
                background = true;
                l = l.substring(0, l.length() - 1);
            }
            int vsindex = -1;
            int veindex = -1;
            while (((vsindex = l.indexOf("${")) >= 0)
                    && ((veindex = l.indexOf("}", vsindex + 2)) > vsindex)) {
                String var = l.substring(vsindex + 2, veindex);
                //System.out.println("var = " + var);
                String val = getval(var);
                //System.out.println("val = " + val);
                l = l.substring(0, vsindex) + val + l.substring(veindex + 1);
            }
            if (l.length() < 1) {
                return true;
            }
            String largs[] = this.splitArgs(l);
            if (largs[0].endsWith(".pvjscript")) {
                File f0 = this.strToFile(largs[0]);
                if (!f0.exists()) {
                    System.err.println(f0.getCanonicalPath() + " does not exist.");
                    return false;
                }
                for (int i = 0; i < largs.length; i++) {
                    this.addTmpVar(Integer.toString(i), largs[i]);
                }
                this.addTmpVar("*", this.arrayToStr(Arrays.copyOfRange(largs, 1, largs.length)));
                this.RunScriptFile(f0);
                return true;
            }
            if (largs[0].compareTo("then") == 0
                    || largs[0].compareTo("do") == 0) {
                if (l.length() < 6) {
                    return true;
                }
                l = l.substring(5);
                if (l.length() < 1) {
                    return true;
                }
                largs = this.splitArgs(l);
            }
            for (int i = 0; i < largs.length; i++) {
                if (largs[i].startsWith("$")) {
                    String aftervar = largs[i].substring(1);
                    String var = "";
                    while (aftervar.length() > 0
                            && Character.isJavaIdentifierPart(aftervar.charAt(0))) {
                        var += aftervar.substring(0, 1);
                        aftervar = aftervar.substring(1);
                    }
                    largs[i] = getval(var) + aftervar;
                } else if (largs[i].startsWith("2>/dev/null")) {
                    largs[i] = "";
                }
            }
            for (int i = 0; i < largs.length; i++) {
                while (((vsindex = largs[i].indexOf('`')) >= 0)
                        && ((veindex = largs[i].indexOf('`', vsindex + 2)) > vsindex)) {
                    String var = largs[i].substring(vsindex + 1, veindex);
                    String val = RunCmd(var);
                    appendDebug("+`" + var + "` produced " + val);
                    largs[i] = largs[i].substring(0, vsindex) + val + largs[i].substring(veindex + 1);
                }
            }
            largs = this.expandFileGlobs(largs);
            if (null == scriptPv) {
                this.setDir(new File(System.getProperty("user.dir")));
                this.initEnvp();
                scriptPv = this.createPv(l);
                CurrentPv = this.scriptPv;
            }
            this.appendDebug("orig=" + l);
            switch (checkBuiltIns(largs)) {
                case 0:
                    appendDebug("<builtin>+" + l, this.scriptPv.getBuiltinStyle());
                    if (null != builtin_output && builtin_output.length() > 0) {
                        scriptPv.appendOut(builtin_output);
                        builtin_output = "";
                    }
                    return true;

                case 1:
                    appendDebug("<builtin>+" + l, this.scriptPv.getBuiltinStyle());
                    if (null != builtin_output && builtin_output.length() > 0) {
                        scriptPv.appendOut(builtin_output);
                        builtin_output = "";
                    }
                    return false;
            }
            this.last_line_through_exception = false;
            if (null != builtin_output && builtin_output.length() > 0) {
                scriptPv.appendOut(builtin_output);
                builtin_output = "";
            }
            if (background) {
                ProcessView pv = this.createPv(this.arrayToStr(largs));
                pv.Start(scriptPv);
                this.addJob(pv);
            } else {
                scriptPv.setCommand(this.arrayToStr(largs));
                scriptPv.Start(scriptPv);
                scriptPv.waitFor();
            }
            return true;
        } catch (Exception exception) {
            this.last_line_through_exception = true;
            exception.printStackTrace();
            if(JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(this,"Continue after error :" +exception.getMessage() +"?")) {
                return true;
            }
        }
        return false;
    }

    private void addTmpVar(String var, String val) {
        if (null == var || null == val) {
            return;
        }
        var = var.trim();
        if (var.length() < 1) {
            System.err.println("empty var name.");
            return;
        }
        val = val.trim();
        if (null == tmpVars) {
            tmpVars = new HashMap<String, String>();
        }
        tmpVars.put(var, val);
        this.appendDebug("addTmpVar( "+var+","+val+")");
    }

    private void addEnvVar(String var, String val) {
        if (null == var || null == val) {
            return;
        }
        var = var.trim();
        if (var.length() < 1) {
            System.err.println("empty var name.");
            return;
        }
        val = val.trim();
        if (null == envp) {
            envp = new String[1];
        } else {
            for (int i = 0; i < envp.length; i++) {
                if (envp[i].startsWith(var + "=")) {
                    envp[i] = var + "=" + val;
                    return;
                }
            }
            String[] old_envp = envp;
            envp = new String[envp.length + 1];
            System.arraycopy(old_envp, 0, envp, 0, old_envp.length);
        }
        envp[envp.length - 1] = var + "=" + val;
        this.setEnvp(envp);
    }

    private String find_rcslib_dir() {
        String rcslib_dir = "";
        try {
            File rcslib_dir_f = null;
            if (rcslib_dir != null && rcslib_dir.length() > 0) {
                rcslib_dir_f = this.strToFile(rcslib_dir);
            }
            if (null == rcslib_dir_f
                    || !rcslib_dir_f.exists()
                    || !rcslib_dir_f.isDirectory()) {
                File store_file =
                        new File(System.getProperty("user.dir"), ".rcslib_dir.txt");

                if (store_file.exists()) {
                    BufferedReader br = new BufferedReader(new FileReader(store_file));
                    String possible_rcslib_dir = br.readLine().trim();
                    File pf = new File(possible_rcslib_dir);
                    if (pf.exists() && pf.isAbsolute() && pf.isDirectory()) {
                        rcslib_dir = pf.getAbsolutePath();
                        return rcslib_dir;
                    }
                    br.close();
                }

                String cp = System.getProperty("java.class.path");
                if (null != cp) {
                    String dirs[] = cp.split(File.pathSeparator);
                    String match_s = File.separator + "rcslib" + File.separator;
                    for (int i = 0; i < dirs.length; i++) {
                        int dir_index = dirs[i].indexOf(match_s);
                        if (dir_index > 0) {
                            String possible_rcslib_dir = dirs[i].substring(0, dir_index + match_s.length());
                            File pf = new File(possible_rcslib_dir);
                            if (pf.exists() && pf.isAbsolute() && pf.isDirectory()) {
                                rcslib_dir = pf.getAbsolutePath();
                            }
                        }
                    }
                }

                rcslib_dir = JOptionPane.showInputDialog("RCS Library Directory?", rcslib_dir);
                if (null == rcslib_dir) {
                    return "";
                }
                rcslib_dir_f = this.strToFile(rcslib_dir);
                if (rcslib_dir_f.exists() && rcslib_dir_f.isDirectory()) {
                    rcslib_dir = rcslib_dir_f.getAbsolutePath();
                }
                this.addEnvVar("RCSLIB_DIR", rcslib_dir);
                PrintStream ps = new PrintStream(new FileOutputStream(store_file));
                ps.println(rcslib_dir);
                ps.close();
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }
        return rcslib_dir;
    }

    private String query_val(String var) {
        String val = "";
        try {
            File rcslib_dir_f = null;
            if (val != null && val.length() > 0) {
                rcslib_dir_f = this.strToFile(val);
            }
            if (null == rcslib_dir_f
                    || !rcslib_dir_f.exists()
                    || !rcslib_dir_f.isDirectory()) {
                File store_file =
                        new File(System.getProperty("user.dir"), "." + var + ".txt");

                if (store_file.exists()) {
                    BufferedReader br = new BufferedReader(new FileReader(store_file));
                    val = br.readLine().trim();
                    br.close();
                }

                val = JOptionPane.showInputDialog(var + " ?", val);
                if (null == val) {
                    return "";
                }
                this.addEnvVar(var, val);
                PrintStream ps = new PrintStream(new FileOutputStream(store_file));
                ps.println(val);
                ps.close();
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }
        return val;
    }

    private void initEnvp() {
        Map<String, String> map = System.getenv();
        for (String var : map.keySet()) {
            this.addEnvVar(var, System.getenv(var));
        }
        Properties p = System.getProperties();
        for (String var : p.stringPropertyNames()) {
            this.addEnvVar(var, p.getProperty(var));
        }
    }
    private int script_line_num = 0;
    private String script_name = "";

    public void appendErr(String s) {
        s = script_name + ":" + script_line_num + " " + s;
        if (null != scriptPv) {
            scriptPv.appendErr(s);
        } else {
            System.err.println(s);
        }
    }

    public void appendDebug(String s, Style style) {
        s = script_name + ":" + script_line_num + " " + s;
        if (null != scriptPv) {
            scriptPv.appendDebug(s, style);
        }
    }

    public void appendDebug(String s) {
        s = script_name + ":" + script_line_num + " " + s;
        if (null != scriptPv) {
            if (this.last_cmd_was_builtin) {
                scriptPv.appendDebug(s, scriptPv.getBuiltinStyle());
            } else {
                scriptPv.appendDebug(s, scriptPv.getExternalStyle());
            }
        }
    }

    public void appendOutPlusErr(String s, Style style) {
        s = script_name + ":" + script_line_num + " " + s;
        if (null != scriptPv) {
            scriptPv.appendOutPlusErr(s, style);
        } else {
            System.err.println(s);
        }
    }
    BufferedReader script_reader = null;
    File script_file = null;
    long script_bytes_read = 0;

    public void RunScriptFile(File f) {
        try {
            val0 = f.getCanonicalPath();
            String user_dir = System.getProperty("user.dir");
            this.setTitle(f.toString() + " : " + user_dir);
            this.setDir(new File(user_dir));
            initEnvp();
            script_file = f;
            script_reader = new BufferedReader(new FileReader(script_file));
            script_name = f.getName();
            scriptPv = this.createPv(f.getName());
            script_line_num = 1;
            addJob(scriptPv);
            this.CurrentPv = scriptPv;
            String l;
            while ((l = script_reader.readLine()) != null) {
                script_bytes_read += l.length() + 1;
                script_line_num++;
                boolean background = false;
                String next_l = null;
                while (l.endsWith("\\")
                        && (next_l = script_reader.readLine()) != null) {
                    script_bytes_read += next_l.length() + 1;
                    script_line_num++;
                    l = l.substring(0, l.length() - 1) + next_l;
                }
                if (l.startsWith("#")) {
                    continue;
                }

                String lines[] = l.split(";");
                for (String lx : lines) {
                    lx = lx.trim();
                    if (lx.startsWith("#")) {
                        continue;
                    }
                    if (!this.ProcessLine(lx, background)) {
                        return;
                    }
                }
            }
            script_reader.close();
            script_reader = null;
        } catch (Exception e) {
            if (null != script_reader) {
                try {
                    script_reader.close();
                    script_reader = null;
                } catch (Exception e2) {
                }
            }
            e.printStackTrace();
        }
    }
    Thread mainThread = null;

    public void startMainThread() {
        if (mainThread != null) {
            mainThread.interrupt();
        }
        mainThread = new Thread(new Runnable() {

            public void run() {
                try {
                    while (!Thread.interrupted()) {
                        String l = lineQueue.take();
                        ProcessLine(l, false);
                    }
                } catch (Exception exception) {
                    exception.printStackTrace();
                }
            }
        });
        mainThread.start();
    }

    public void Run(final String args[]) {
        this.startMainThread();
        int starting_arg = 0;
        for (starting_arg = 0; starting_arg < args.length; starting_arg++) {
            if (!args[0].startsWith("-")) {
                break;
            }
            if (args[0].compareTo("--debug") == 0
                    || args[0].compareTo("-d") == 0) {
                this.vw_state = ViewState.ViewStdOutAndStdErrAndDebug;
            }
        }
        if (System.getenv("DEBUG") != null) {
            this.vw_state = ViewState.ViewStdOutAndStdErrAndDebug;
        }
        lineQueue.add(arrayToStr(args, starting_arg));
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        final String fargs[] = args;
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                Main pvjf = new Main();
                pvjf.setVisible(true);
                pvjf.Run(fargs);
            }
        });
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.ButtonGroup buttonGroupVw;
    private javax.swing.JCheckBoxMenuItem jCheckBoxMenuItemAutoScroll;
    private javax.swing.JDialog jDialogEnvp;
    private javax.swing.JMenu jMenu1;
    private javax.swing.JMenu jMenu2;
    private javax.swing.JMenuBar jMenuBar1;
    private javax.swing.JMenuItem jMenuItem1;
    private javax.swing.JMenuItem jMenuItem2;
    private javax.swing.JMenuItem jMenuItemOpen;
    private javax.swing.JMenuItem jMenuItemSetScrollLimit;
    private javax.swing.JMenu jMenuOptions;
    private javax.swing.JMenu jMenuProcess;
    private javax.swing.JMenu jMenuTools;
    private javax.swing.JRadioButtonMenuItem jRadioButtonMenuItemViewBoth;
    private javax.swing.JRadioButtonMenuItem jRadioButtonMenuItemViewDebug;
    private javax.swing.JRadioButtonMenuItem jRadioButtonMenuItemViewStdErr;
    private javax.swing.JRadioButtonMenuItem jRadioButtonMenuItemViewStdOut;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPaneEnvpTable;
    private javax.swing.JTable jTableEnvp;
    private javax.swing.JTextField jTextFieldCmd;
    private javax.swing.JTextPane jTextPane1;
    // End of variables declaration//GEN-END:variables
}
